#include "include/rpc_client.h"
#include "include/rpc_helper.h"
#include "rpc/client_processor.h"
#include "rpc/protocol.h"
#include "rpc/connector.h"
#include "rpc/connection.h"
#include "rpc/poller.h"

namespace urpc {
RpcClient::RpcClient(EventManager* poller, const std::string& server_ip,
                     uint16 server_port, const std::string& client_ip,
                     uint16 client_port, uint32 timeout)
    : event_manager_(poller), server_ip_(server_ip), server_port_(server_port), client_ip_(
        client_ip), client_port_(client_port), timeout_(timeout) {
  processor_.reset(new ClientProcessor(event_manager_.get()));
  connector_.reset(new Connector(event_manager_.get()));
}

RpcClient::~RpcClient() {
  StopStreamFromClient();
}

void RpcClient::CallMethod(const MethodDescriptor* method,
                           RpcController* controller, const Message* request,
                           Message* response, google::protobuf::Closure* done) {
  ClientProcessor::RpcRequestInfo* req = new ClientProcessor::RpcRequestInfo;
  req->rpc_id = GetNextRpcId();
  req->func_id = HandlerMap::GetFunidByMethodDescriptor(req->method);
  req->method = method;
  req->controller = controller;
  req->request = request;
  req->response = response;
  req->done = done;

  processor_->CallMethod(req);
}

bool RpcClient::Init() {
  std::string server_ip, client_ip;
  uint16 server_port, client_port;
  uint32 timeout;

  {
    ScopedMutex l(&ip_mutex_);
    server_ip = server_ip_;
    server_port = server_port_;
    client_ip = client_ip_;
    client_port = client_port_;
    timeout = timeout_;
  }

  Connection* conn = connector_->Connect(server_ip, server_port, client_ip,
                                         client_port, timeout);
  if (conn == NULL) {
    return false;
  }
  conn->SetProtocol(new Protocol);
  conn->SetProcessor(processor_.get());
  conn->SetCloseClosure(reconnect_cb_.get());  //fixme: del twice
  processor_->SetConnection(conn);

  return true;
}

void RpcClient::StopStreamFromClient() {
}

bool RpcClient::SwitchServer(const std::string& ip, uint16 port) {
  {
    ScopedMutex l(&ip_mutex_);
    server_ip_ = ip;
    server_port_ = port;
  }

  StopStreamFromClient();

  return Init();
}

bool RpcClient::Reconnect() {
  StopStreamFromClient();

  if (Init() && reconnect_cb_.get() != NULL) {
    reconnect_cb_->Run();
    return true;
  }

  return false;
}
}
